package com.hemerasolutions.v2trainer.model.training.statistic;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;














import com.hemerasolutions.v2trainer.model.base.BaseValueHolder;
import com.hemerasolutions.v2trainer.model.exercise.Exercise;
import com.hemerasolutions.v2trainer.model.exercise.executions.Execution;
import com.hemerasolutions.v2trainer.model.exercise.intensity.IntensityZone;
import com.hemerasolutions.v2trainer.model.training.TrainingStep;
import com.hemerasolutions.v2trainer.model.unit.volume.VolumeType;
import com.hemerasolutions.v2trainer.util.Utility;

@Entity
public class TrainingStatistic extends BaseValueHolder {
 
	private static final long serialVersionUID = 1L;

	@ManyToOne
	private TrainingStep trainingStep;
	
    @ManyToOne    
	private Exercise exercise;

    @ManyToOne    
    private Execution execution;
    
    @ManyToOne
    private IntensityZone intensityZone;

    @ManyToOne
    private VolumeType volumeType;
	    
    @Column    
	private Date actionTime;

    @Column
    private Date restTime;
    
    @Column
    private Date totalTime;    
 
    @Column
	private int statisticType;	


    @OneToMany(mappedBy="stepStatistic", cascade=CascadeType.ALL,orphanRemoval=true)
	private List<Statistic> statistics;

    public static final int ROOT_STATISTIC = 0;
    
    public static final int EXERCISE_STATISTIC = 1;

    public static final int REST_STATISTIC = 2;

    public static final int GROUP_STATISTIC = 3;
    
    
	public TrainingStatistic() {
		super();
		this.statistics = new ArrayList<Statistic>();
	}

	public TrainingStatistic(TrainingStep ts, TrainingStatistic other){
		this();
		this.actionTime = other.actionTime;
		this.execution = other.execution;
		this.exercise = other.exercise;
		this.intensityZone = other.intensityZone;
		this.restTime = other.restTime;
		this.totalTime = other.totalTime;
		this.statisticType = other.statisticType;		
		this.value = other.value;		
		this.volumeType = other.volumeType;
		this.volumeFactor = other.volumeFactor;

		this.trainingStep = ts;
		
		for(Statistic statistic:other.statistics){
			this.statistics.add(new Statistic(this,statistic));
		}
	}

	public TrainingStatistic(TrainingStep ts,int statisticType) {
		this();
		this.statisticType = statisticType;
		this.trainingStep = ts;
	}

	public void addArbritaryUnit(StatisticUnit unit) {

		boolean founded = false;
		
		for(Statistic statistic:this.getStatistics()){
			if(statistic.getStatisticUnit().equals(unit)){
				founded = true;
			}
		}

		if(!founded){
			this.statistics.add(new Statistic(this,unit));
		}
	
	}

	public void removeArbritaryUnit(StatisticUnit unit) {
		for(Statistic statistic:this.getStatistics()){
			if(statistic.getStatisticUnit().equals(unit)){
				this.statistics.remove(statistic);
				break;
			}
		}
	}

	public boolean isSumCompatible(TrainingStatistic other){

		if(	this.statisticType == TrainingStatistic.EXERCISE_STATISTIC &&
			other.statisticType	== TrainingStatistic.EXERCISE_STATISTIC){
					
			if( this.getExercise().equals(other.getExercise()) && 
				this.getVolumeType().equals(other.getVolumeType())	){
				if( this.getExecution() == null || other.getExecution() == null ||
					this.getIntensityZone() == null || other.getIntensityZone() == null ){

					if(this.getExecution() == null || other.getExecution() == null){
						if(this.getExecution() == null && other.getExecution() == null){
							if(this.getIntensityZone() == null && other.getIntensityZone() == null){
								return true;
							}
						}
					}else if(this.getExecution().equals(other.getExecution())){
						if(this.getIntensityZone() == null || other.getIntensityZone() == null){
							if(this.getIntensityZone() == null && other.getIntensityZone() == null){
								return true;
							}
						}else if(this.getIntensityZone().equals(other.getIntensityZone())){
							return true;
						}
						
					}
					
				}else if( this.getExecution().equals(other.getExecution()) &&
						  this.getIntensityZone().equals(other.getIntensityZone())){

					return true;
				}
				
			}
			
		
		}else if( (this.getStatisticType() 		== TrainingStatistic.REST_STATISTIC ||
					this.getStatisticType() 	== TrainingStatistic.GROUP_STATISTIC) 	&&
				  (this.getStatisticType() 		== TrainingStatistic.REST_STATISTIC ||
				  this.getStatisticType() 		== TrainingStatistic.GROUP_STATISTIC  )){
			return true;
		}		

		return false;
	}

	public void calcStatistics() {
		List<Statistic> statisticAux = new ArrayList<Statistic>();
		statisticAux.addAll(this.statistics);
		boolean founded = false;
		
		
		for(Statistic statistic:statisticAux){
			if(!this.trainingStep.getStatisticUnits().contains(statistic.getStatisticUnit())){
				this.statistics.remove(statistic);
			}
		}
		
		
		for(StatisticUnit statisticUnitTs:this.trainingStep.getStatisticUnits()){
			for(Statistic statistic:this.getStatistics()){
				if(statisticUnitTs.equals(statistic.getStatisticUnit())){
					statistic.calcStatistic();
					founded = true;
				}
			}

			if(!founded){
				Statistic statistic = new Statistic(this,statisticUnitTs);
				statistic.calcStatistic();
				this.statistics.add(statistic);
			}
		}
	}

	public void multiply(int multiplier){
		long newActionTime = Utility.dateToLong(this.actionTime) * multiplier;
		long newRestTime =  Utility.dateToLong(this.restTime) * multiplier;
		
		this.actionTime = Utility.longToDate(newActionTime); 
		this.restTime   = Utility.longToDate(newRestTime); 
		this.totalTime  = Utility.longToDate(newActionTime + newRestTime);
		for(Statistic statistic:this.statistics){
			statistic.multiply(multiplier);
		}		
	}

	public void sum(TrainingStatistic other) {
		long newActionTime = Utility.dateToLong(this.actionTime) +  Utility.dateToLong(other.actionTime);
		long newRestTime =  Utility.dateToLong(this.restTime) + Utility.dateToLong(other.restTime);
		boolean founded = false;
		List<Statistic> tempStatistics = new ArrayList<Statistic>();
		
		
		this.actionTime = Utility.longToDate(newActionTime); 
		this.restTime   = Utility.longToDate(newRestTime); 
		this.totalTime  = Utility.longToDate(newActionTime + newRestTime);
		this.value 		= this.value + other.value;

		if( this.statisticType == EXERCISE_STATISTIC || 
			this.statisticType == ROOT_STATISTIC	){

			for(StatisticUnit iu:this.trainingStep.getStatisticUnits()){
				founded = false;
				for(Statistic statistic:this.statistics){
					if(statistic.getStatisticUnit().equals(iu)){
						tempStatistics.add(statistic);
						founded = true;
					}
				}
				if(!founded){
					tempStatistics.add(new Statistic(this,iu));
				}
			}
			for(Statistic statistic:tempStatistics){
				for(Statistic statisticAux:other.getStatistics()){
					if(	statistic.getStatisticUnit().equals(statisticAux.getStatisticUnit())){
						statistic.sum(statisticAux);
					}
				}
			
			}
			this.statistics = tempStatistics;
		}		
	}

	public void clear(){
		this.actionTime = Utility.longToDate(0); 
		this.restTime   = Utility.longToDate(0); 
		this.totalTime  = Utility.longToDate(0);
		this.value 		= 0;

		for(Statistic statistic:this.statistics){
			statistic.setValue(0);
		}
		
	}	
	
	public double getRealValue(){
		return this.value;
	}

	public void setRealValue(double value){
		this.value = value;
	}
	
	public Execution getExecution() {
		return execution;
	}

	public void setExecution(Execution execution) {
		this.execution = execution;
	}

	public IntensityZone getIntensityZone() {
		return intensityZone;
	}

	public void setIntensityZone(IntensityZone intensityZone) {
		this.intensityZone = intensityZone;
	}

	public List<Statistic> getStatistics() {
		return statistics;
	}

	public void setStatistics(List<Statistic> statistics) {
		this.statistics = statistics;
	}

	public Date getActionTime() {
		return actionTime;
	}

	public void setActionTime(Date actionTime) {
		this.actionTime = actionTime;
	}

	public Date getRestTime() {
		return restTime;
	}

	public void setRestTime(Date restTime) {
		this.restTime = restTime;
	}

	public Date getTotalTime() {
		return totalTime;
	}

	public void setTotalTime(Date totalTime) {
		this.totalTime = totalTime;
	}

	public Exercise getExercise() {
		return exercise;
	}

	public void setExercise(Exercise exercise) {
		this.exercise = exercise;
	}
	
	public TrainingStep getTrainingStep() {
		return trainingStep;
	}


	public void setTrainingStep(TrainingStep trainingStep) {
		this.trainingStep = trainingStep;
	}


	public VolumeType getVolumeType() {
		return volumeType;
	}

	public void setVolumeType(VolumeType volumeType) {
		this.volumeType = volumeType;
	}

	public int getStatisticType() {
		return statisticType;
	}

	public void setStatisticType(int statisticType) {
		this.statisticType = statisticType;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		result = prime * result
				+ ((trainingStep == null) ? 0 : trainingStep.hashCode());
		result = prime * result + ((uuid == null) ? 0 : uuid.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		TrainingStatistic other = (TrainingStatistic) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		if (trainingStep == null) {
			if (other.trainingStep != null)
				return false;
		} else if (!trainingStep.equals(other.trainingStep))
			return false;
		if (uuid == null) {
			if (other.uuid != null)
				return false;
		} else if (!uuid.equals(other.uuid))
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "TrainingStatistic [id=" + id + ", trainingStep=" + trainingStep
				+ ", uuid=" + uuid + "]";
	}

}

 
